//==================================================
//Instituto Tecnologico de Costa Rica
//Principios de Sistemas Operativos 
//Profesora: Ericka Marin 
//Tarea Programada 1
//Integrantes:
//Roland Chaverri
//Gabriel Rodriguez Brenes
//==================================================
/**
 *Modalidad thread
 */
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
#include "mode_THREAD.h"
#include "list.c"
#define BUF_SIZE 255
#define PORT 80
#define USERAGENT "HTMLGET 1.0"
//------------------------------------------------------


//Pagina prueba
/*http://www.web-source.net/html_codes_chart.htm*/
/**
 * Metodo para bajar con THREAD
 */
void bajar_THREAD(char *pagina)
{
    pthread_t idHilo;
    pthread_attr_t attr;
    /*inicializa los parámetros de los threads por defecto*/
    pthread_attr_init (&attr);

    pthread_create(&idHilo, NULL, funcion, (void*)pagina);
}

/*
 * Hilo para realizar la descarga de la pagina
 * @param args
 * @return 
 */
void *funcion(void *args)
{
    char *pagina;
    pagina = (char *)args;
    char *host = pagina;
    char *page = pagina;
    
/*
    host = "www.web-source.net";
    page = "html_codes_chart.htm";
*/
    //Archivo para guardar la pagina
    FILE *archivo;/*El manejador de archivo*/
    archivo = fopen(page, "w");
    //Socket
    struct sockaddr_in *remote;
    int sock;
    int tmpres;
    char *ip;
    char *get;
    char buf[BUFSIZ+1];
    
    //(char *) param
    printf("Host: %s\n", host);
    printf("Pagina: %s\n", page);
    //host = (char*)args;
    
    if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
        perror("No puede crear el socket TCP");
        //exit(1);
    }
    ip = get_ip(host);
    fprintf(stderr, "IP is %s\n", ip);
    remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
    remote->sin_family = AF_INET;
    tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));

    if(tmpres < 0){
        perror("No se puede configuar");
        exit(1);
    }else if(tmpres == 0){
        fprintf(stderr, "%s No es una direccion IP valida\n", ip);
        exit(1);
    }
    remote->sin_port = htons(PORT);
    //Conectar la pagina
    if(connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
        perror("No se puede conectar");
        exit(1);
    }
    get = build_get_query(host, page);
    fprintf(stderr, "\n<<START>>\n%s<<END>>\n", get);

    //Envia la solicitud al servidor
    int sent = 0;
    while(sent < strlen(get))
    {
        tmpres = send(sock, get + sent, strlen(get) - sent, 0);
        if(tmpres == -1){
            perror("No se puede enviar la solicitud");
            exit(1);
        }
        sent += tmpres;
    }
   
    memset(buf, 0, sizeof(buf));
    int htmlstart = 0;
    char *htmlcontent;
     //Recibe la pagina
    while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0)
    {
        if(htmlstart == 0){
            htmlcontent = strstr(buf, "\r\n\r\n");
            if(htmlcontent != NULL){
                htmlstart = 1;
                htmlcontent += 4;
            }
        }else{
            htmlcontent = buf;
        }
        if(htmlstart){
            fprintf(stdout, "%s", htmlcontent);
        }
        fprintf(archivo, "%s", htmlcontent);/*Escribimos en el archivo*/

        memset(buf, 0, tmpres);
    }
    
    if(tmpres < 0){
        perror("Error recibiendo datos");
    }
    
    free(get);
    free(remote);
    free(ip);
    fclose(archivo);
    close(sock);
    
    pthread_exit(NULL); /* Provoca la terminación del thread*/
}

/*
 * Hilo para realizar la descarga de la pagina
 * @param args
 * @return 
 */
void bajar(char *host, char *page, char *carpeta)
{
    printf("bajar host: %s\n", host);
    printf("bajar pagina: %s\n", page);
    
    //Archivo para guardar la pagina
    FILE *archivo;/*El manejador de archivo*/
/*
    char *path = strcat(carpeta, page);
    printf("%s", path);
*/
    archivo = fopen(page, "w");
    //Socket
    struct sockaddr_in *remote;
    int sock;
    int tmpres;
    char *ip;
    char *get;
    char buf[BUFSIZ+1];
    
    //(char *) param
    //host = (char*)args;
    
    if((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0){
        perror("No puede crear el socket TCP");
        //exit(1);
    }
    ip = get_ip(host);
    //fprintf(stderr, "IP is %s\n", ip);
    remote = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in *));
    remote->sin_family = AF_INET;
    tmpres = inet_pton(AF_INET, ip, (void *)(&(remote->sin_addr.s_addr)));

    if(tmpres < 0){
        perror("No se puede configuar");
        exit(1);
    }else if(tmpres == 0){
        fprintf(stderr, "%s No es una direccion IP valida\n", ip);
        exit(1);
    }
    remote->sin_port = htons(PORT);
    //Conectar la pagina
    if(connect(sock, (struct sockaddr *)remote, sizeof(struct sockaddr)) < 0){
        perror("No se puede conectar");
        exit(1);
    }
    get = build_get_query(host, page);
    //fprintf(stderr, "\n<<START>>\n%s<<END>>\n", get);

    //Envia la solicitud al servidor
    int sent = 0;
    while(sent < strlen(get))
    {
        tmpres = send(sock, get + sent, strlen(get) - sent, 0);
        if(tmpres == -1){
            perror("No se puede enviar la solicitud");
            exit(1);
        }
        sent += tmpres;
    }
   
    memset(buf, 0, sizeof(buf));
    int htmlstart = 0;
    char *htmlcontent;
     //Recibe la pagina
    while((tmpres = recv(sock, buf, BUFSIZ, 0)) > 0)
    {
        if(htmlstart == 0){
            htmlcontent = strstr(buf, "\r\n\r\n");
            if(htmlcontent != NULL){
                htmlstart = 1;
                htmlcontent += 4;
            }
        }else{
            htmlcontent = buf;
        }
        if(htmlstart){
            //fprintf(stdout, "%s", htmlcontent);
        }
        fprintf(archivo, "%s", htmlcontent);/*Escribimos en el archivo*/

        memset(buf, 0, tmpres);
    }
    
    if(tmpres < 0){
        perror("Error recibiendo datos");
    }
    
    free(get);
    free(remote);
    free(ip);
    fclose(archivo);
    close(sock);
}

/**
 * Obtiene el IP del host
 * @param host
 * @return
 */
char *get_ip(char *host)
{
    struct hostent *hent;
    int iplen = 15; //XXX.XXX.XXX.XXX
    char *ip = (char *)malloc(iplen + 1);
    memset(ip, 0, iplen + 1);
    if((hent = gethostbyname(host)) == NULL)
    {
        herror("No se puede obtener el IP");
        exit(1);
    }
    if(inet_ntop(AF_INET, (void *)hent->h_addr_list[0], ip, iplen) == NULL)
    {
        perror("No se puede resolver la direccion");
        exit(1);
    }
    return ip;
}

/**
 * Construye la solicitud para bajar la pagina
 * @param host
 * @param page
 * @return 
 */
char *build_get_query(char *host, char *page)
{
    char *query;
    char *getpage = page;
    char *tpl = "GET /%s HTTP/1.0\r\nHost: %s\r\nUser-Agent: %s\r\n\r\n";
    if(getpage[0] == '/'){
        getpage = getpage + 1;
        fprintf(stderr,"Removing leading \"/\", converting %s to %s\n", page, getpage);
    }
    // -5 is to consider the %s %s %s in tpl and the ending \0
    query = (char *)malloc(strlen(host) + strlen(getpage) + strlen(USERAGENT) + strlen(tpl) - 5);
    sprintf(query, tpl, getpage, host, USERAGENT);
    return query;
}

void leer_archivos()
{
    FILE *archivo;
    char *linea;
    char *buffer;
    int buff_max = 1024;

    if ((buffer=(char*)malloc(buff_max))==NULL)
        perror("can't allocate memory for line buffer");

    archivo = fopen("prueba.html","r");

    if (archivo == NULL){
        printf("\nError de apertura del archivo. \n\n");
    }else{
        printf("\nEl contenido del archivo de prueba es \n\n");
        while (feof(archivo) == 0)
        {
            linea = fgets(buffer, buff_max ,archivo);
            printf("+%s", linea);
            
            char *pagina = strtok(linea, "<> ");
            while(pagina != NULL)
            {
                //pagina = strtok(pagina, NULL);
                printf("*%s\n", pagina);
                pagina = strtok(NULL, "<> ");
            }
        }
    }
    fclose(archivo);
}


void *baja_links(void *args)
{
/*
    PAGE *pag;
    pag = head;

    while(pag)
    {
        printf("%s\n", pag->direccion);
        pag = pag->siguiente;
    }
*/
}

void start()
{
    pthread_t idHilo;
    pthread_create(&idHilo, NULL, baja_links, NULL);
}

/**
 * Descarga la pagina
 * @param URL
 * @param profundidad
 * @return
 */
URL pagina_separada(char *url)
{
    char *result;
    char newURL[strlen(url) + 1];
    strcpy(newURL, url);
    result = strtok(newURL, "/");
    
    char* h, *p;
    int cont = 0;
    char *init;
    init = result;
    
    //Aqui se revisa si la pagina empieza con http o no
    while( result != NULL )
    {
        if(strcmp(init, "http:") != 0 && cont == 0)
        {
            h = result;
        }
        else if(cont == 0)
        {
            result = strtok( NULL, "/");
            h = result;   
        }
        
        result = strtok( NULL, "/");
        if(result != NULL)
        {
            p = result;
        }
        cont++;
    }
    URL url_split;
    url_split.host = h;
    url_split.page = p;
    
    printf("HOST: %s\n\r", url_split.host);
    printf("PAGE: %s\n\r", url_split.page);
    bajar(h, p, "pagina");
    return url_split;
}

int main()
{    
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775115.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775123.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775172.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775116.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775232.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775229.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775144.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775187.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775194.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775219.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775211.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775175.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2763032.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775391.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775393.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775395.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775189.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775398.html");
    insertar("http://www.aldia.cr/ad_ee/2011/mayo/12/deportes2775308.html");
    insertar("http://www.web-source.net/html_tips.htm");
    insertar("http://www.web-source.net/html_codes_chart.htm");
    insertar("http://www.web-source.net/web_development.htm");
    
    //insertar("http://www.web-source.net/web_design_tips");
    insertar("http://www.web-source.net/javascript_codes.htm");
    insertar("http://www.web-source.net/216_color_chart.htm");
    //start();
    //pagina_separada("http://www.web-source.net/216_color_chart.htm");
    
    PAGE *page;
    page = head;
    
    while(page)
    {
        pagina_separada(page->direccion);
        
        page = page->siguiente;
    }
   
    /*La propia función main es un thread
    /*inicializa los parámetros de los threads por defecto*/
   
    //bajar_THREAD("http://www.web-source.net/html_codes_chart.htm");
    

    //leer_archivos();
    return 1;
}